package com.summer.authentication.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.summer.authentication.mapper.XcUserMapper;
import com.summer.authentication.mapper.XcUserRoleMapper;
import com.summer.authentication.model.AuthParams;
import com.summer.authentication.model.dto.XcUserDto;
import com.summer.authentication.pojo.XcUser;
import com.summer.authentication.pojo.XcUserRole;
import com.summer.authentication.service.AuthService;
import com.summer.authentication.service.VxLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.Map;

@Service("wx")
@Slf4j
public class VxAuth implements AuthService, VxLoginService {

    @Autowired
    private RestTemplate restTemplate;

    // 系统的域名或根路径，用于重定向到登录页
    @Value("${serve_url}")
    private String serveUrl;

    @Autowired
    private XcUserMapper userMapper;

    @Autowired
    private XcUserRoleMapper userRoleMapper;

    // 使用代理对象调用事务方法，防止事务失效
    @Autowired
    private VxAuth vxAuth;

    /**
     * wx认证校验接口
     *
     * @param authParams 登录提交的参数
     * @return 返回用于生成用户信息的JTW
     */
    @Override
    public XcUserDto authExecute(AuthParams authParams) {
        //1. 根据unionid查到用户信息, 前端把username当成unionid了
        String wxUnionId = authParams.getUsername();
        XcUser xcUser = userMapper.selectOne(new LambdaQueryWrapper<XcUser>()
                .eq(wxUnionId != null, XcUser::getWxUnionid, wxUnionId));
        if (xcUser == null) {
            throw new RuntimeException("notFoundVxUser");
        }

        //2. 封装用户信息返回
        XcUserDto xcUserDto = new XcUserDto();
        BeanUtils.copyProperties(xcUser, xcUserDto);

        return xcUserDto;
    }

    @Override
    public String vxLogin(String code) {
        Map<String, String> userInfo = null;
        try{
            //1. 携带授权码调用微信接口获取微信token
            Map<String, String> vxToken = getVxToken(code);
            String token = vxToken.get("access_token");
            String openid = vxToken.get("openid");
            String errcode = vxToken.getOrDefault("errcode", "");
            if (!StringUtils.isEmpty(errcode)){
                throw new RuntimeException(vxToken.get("errmsg"));
            }

            //2. 携带微信token获取用户信息
            userInfo = getUserInfoByToken(token, openid);
            String errcode1 = userInfo.get("errcode");
            if (!StringUtils.isEmpty(errcode1)){
                throw new RuntimeException(userInfo.get("errmsg"));
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("登陆失败，请重试");
        }

        //3. 若用户未注册则保存用户信息到数据库中
        String unionid = userInfo.get("unionid");
        XcUser xcUser = userMapper.selectOne(new LambdaQueryWrapper<XcUser>()
                .eq(unionid != null, XcUser::getWxUnionid, unionid));
        if (xcUser == null){
            vxAuth.saveUserInfo(userInfo);
        }

        //4. 重定向到本系统的统一登录接口进行登录，authType为wx_login
        // TODO 在此系统的登录页中如果带authType=wx的请求参数就去请求登录接口，登录接口返回的JWT响应给浏览器，浏览器进行存储JWT
        //      千万别直接调用authExecute()方法，这个方法必须是登录接口调用才能返回JWT给浏览器，而此方法是微信远程回调过来的
        String loginPage = "/sign.html?username=" + xcUser.getUsername() + "&authType=wx";
        return "redirect:" + serveUrl + loginPage;
    }


    /**
     * 微信返回用户信息后将用户信息存入user、user_role表
     *
     * @param userInfo 用户信息
     */
    @Transactional
    public void saveUserInfo(Map<String, String> userInfo) {
        // 保存到user表
        XcUser xcUser = new XcUser();
        xcUser.setName(userInfo.get("nickname"));
        xcUser.setUsername(userInfo.get("unionid"));
        xcUser.setUtype("101001"); // 学生类型
        xcUser.setWxUnionid(userInfo.get("unionid"));
        xcUser.setStatus("1");
        xcUser.setCreateTime(LocalDateTime.now());
        userMapper.insert(xcUser);

        // 保存到user_role表
        XcUserRole xcUserRole = new XcUserRole();
        // MP框架已自动生成UUID并set到xcUser对象中了
        xcUserRole.setUserId(xcUser.getId());
        // 默认角色为学生
        xcUserRole.setRoleId("17");
        xcUserRole.setCreator("陈靓仔");
        xcUserRole.setCreateTime(LocalDateTime.now());
        userRoleMapper.insert(xcUserRole);
    }

    /**
     * 携带微信token获取用户信息
     *
     * @param token access_token
     * @return 返回用户信息
     */
    private Map<String, String> getUserInfoByToken(String token,String openid) {
        String getUserInfoUrl = "http://localhost:8843/getInfo";
        String param = "?access_token=" + token + "&openid=" + openid;
        String result = restTemplate.getForObject(getUserInfoUrl + param, String.class);
        return JSON.parseObject(result, Map.class);
    }

    /**
     * 发送请求获取微信token
     *
     * @param code 授权码
     * @return token
     */
    private Map<String, String> getVxToken(String code) {
        // 模拟微信获取token的接口地址
        String vxTokenUrl = "http://localhost:8843/getAccessToken";
        String param = "?code=" + code;
        String result = restTemplate.getForObject(vxTokenUrl + param, String.class);
        return JSON.parseObject(result, Map.class);
    }
}
